package main

import (
	"fmt"
	"go/types"
)

/*
流程控制之switch

	switch语句执行的过程自上而下，直到找到case匹配项，匹配项中无须使用break，因为Go语言中的switch默认给每个case自带break，但是java却不是，默认不自带break。

	TIPS：
		· 可以添加fallthrough（中文含义是：贯穿），强制执行后面的第一个case分支。fallthrough必须放在某case分支代码块的最后一行；
		· case后的值不能重复，但可以同时测试多个符合条件的值，这些值之间使用逗号分隔，例如：case val1, val2, val3；
		· switch后的表达式可以省略，默认是 switch true
*/
func main() {

	grad := ""
	grade := 80

	/*
		一. switch后的表达式省略。默认是switch true 的判断
	*/
	switch {

	case grade >= 90 && grade <= 100:
		grad = "A"
		// 可有可无，因为Go语言中的switch默认给每个case自带break
		break
	case grade >= 80 && grade < 90:
		grad = "B"
	case grade >= 60 && grade < 80:
		grad = "C"
	default:
		grad = "不及格"
	}
	fmt.Println("成绩等级为：", grad)

	/*
		二. case后的值不能重复，但可以同时测试多个符合条件的值
	*/
	month := 9
	switch month {

	case 1, 3, 5, 7, 8, 10, 12:
		fmt.Println("这个月31天")
	case 2:
		fmt.Println("这个月28或29天")
	default:
		fmt.Println("这个月30天")
	}

	/*
		三. 可以添加fallthrough（中文含义是：贯穿），强制执行后面的第一个case分支。fallthrough必须放在case分支的最后一行。
			TIPS：fallthrough 是为了兼容 C 语言的 case 设计的，不建议使用
	*/
	i := 10
	switch i {
	case 1, 3, 5, 7, 8, 10, 12:
		fmt.Println("这个月31天")
		// 如果 case 到了这个代码块，但是注释掉了 fallthrough ，就算后面的 case 代码块中有 fallthrough 也不会执行
		fallthrough
	case 2:
		fmt.Println("这个月28天")
		// 前面的 case 中代码块被执行，所以作为后面的第一个case，此 case 中的代码块将会被执行。然后此 case 代码块中又包含了 fallthrough，所以后面的 case 的代码还会继续被执行
		fallthrough
	case 4, 6, 9, 11:
		fmt.Println("这个月30天")
		//fallthrough
	default:
		fmt.Println("未定义的月份")
	}

	/*
		四. switch语句还可以被用于type switch（类型转换）来判断某个interface变量中实际存储的变量类型
	*/
	var xx interface{} // 空接口。空接口中没有任何方法，任意类型都可以实现该接口

	switch ii := xx.(type) {
	case types.Nil:
		fmt.Println(" xx 的类型：", ii)
	case int:
		fmt.Println(" xx 是int型")
	case float32:
		fmt.Println(" xx 是float32型")
	case func(int):
		fmt.Println(" xx 是func(int)型")
	case bool, string:
		fmt.Println(" xx 是bool或string型")
	default:
		fmt.Println(" xx 未知类型")
	}
}
